package com.omega.framework.common.util.thread;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 线程池工具类
 *
 * @author Lv.
 * @date 2023/1/3 17:24
 */
@Slf4j
public class ThreadPoolUtil {

    /**
     * 核心线程数
     */
    public static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors();
    /**
     * 最大线程数
     */
    public static final int MAX_POOL_SIZE = CORE_POOL_SIZE * 5;
    /**
     * 任务队列大小
     */
    public static final int QUEUE_CAPACITY = MAX_POOL_SIZE * 100;
    /**
     * 线程最大空闲时间
     */
    public static final int KEEP_ALIVE_TIME = 0;
    /**
     * 有界阻塞队列
     */
    private static final LinkedBlockingQueue<Runnable> BLOCKING_QUEUE = new LinkedBlockingQueue<>(1000);

    /**
     * 创建指定线程数量的线程池
     *
     * @param threadCount
     * @return
     */
    public static ThreadPoolExecutor createThreadPoolByCount(int threadCount) {
        return new ThreadPoolExecutor(threadCount, threadCount,
                60L, TimeUnit.SECONDS, BLOCKING_QUEUE, new ThreadPoolExecutor.CallerRunsPolicy());
    }

    /**
     * @param corePoolSize      核心线程数
     * @param maximumPoolSize   最大线程数
     * @param blockingQueueSize 工作队列：阻塞队列
     * @param threadPoolName    线程池名称
     * @return
     */
    public static ThreadPoolExecutor createThreadPoolByName(int corePoolSize, int maximumPoolSize, int blockingQueueSize, String threadPoolName) {
        //默认空闲线程最大存活时间60秒
        return new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(blockingQueueSize), new NamedThreadFactory(threadPoolName), new ThreadPoolExecutor.CallerRunsPolicy());
    }

    public static ThreadPoolTaskExecutor getExecutor() {
        return ThreadPoolHolder.EXECUTOR;
    }

    public static void execute(Runnable command) {
        ThreadPoolHolder.EXECUTOR.execute(command);
    }

    /**
     * 内部类和静态变量初始化保证线程安全，未被调用时，线程池不会被创建
     */
    private static class ThreadPoolHolder {

        /**
         * 线程名前缀
         */
        private static final String THREAD_NAME_PREFIX = "async-pool-";
        /**
         * 线程池
         */
        private static final ThreadPoolTaskExecutor EXECUTOR = buildThreadPoolTaskExecutor();

        /**
         * 初始化线程池
         */
        private static ThreadPoolTaskExecutor buildThreadPoolTaskExecutor() {
            log.info(THREAD_NAME_PREFIX + "初始化");
            //线程池初始化
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            // 核心线程数
            executor.setCorePoolSize(CORE_POOL_SIZE);
            // 最大线程数
            executor.setMaxPoolSize(MAX_POOL_SIZE);
            // 任务队列大小
            executor.setQueueCapacity(QUEUE_CAPACITY);
            // 线程前缀名
            executor.setThreadNamePrefix(THREAD_NAME_PREFIX);
            // 线程的空闲时间
            executor.setKeepAliveSeconds(KEEP_ALIVE_TIME);
            // 拒绝策略
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            //用来设置线程池关闭的时间等待所有任务都完成在继续销毁其他的Bean，这样这些异步任务的销毁就会先于Redis线程池的销毁
            executor.setWaitForTasksToCompleteOnShutdown(true);
            //该方法用来设置线程池中任务的等待时间，如果超过这个时间还没有销毁就强制销毁，以确保应用最后能够被关闭，而不是阻塞住
            executor.setAwaitTerminationSeconds(10);
            // 线程初始化
            executor.initialize();
            return executor;
        }

    }
}
